#!/usr/bin/python
import subprocess as sp
import re, time, sys,getopt,csv
from Bio import SeqIO
from Bio.Seq import Seq
import argparse
from os import makedirs
import os

#Load rule and generate regex for candidateTargets
def createCandTargRegex(rule):
    targetRule = ''
    if len(rule) <= 23:
        targetRule+='[ACTG]{{{}}}'.format(23-len(rule))
    for i in rule:
        if i in 'BbNn':
            targetRule+='[ACTG]'
        else:
            targetRule+='[{}]'.format(i)
    targetRe = re.compile(targetRule, re.IGNORECASE)
    return targetRe


#Loads a FASTA file and creates a string <candidate_seq> from the sequence.
def createCandSeqStr(faname):
    f = open(faname)
    try:
        faObj = SeqIO.read(f,'fasta')
        candidateSequence = faObj.seq.tostring()
        rcCandidateSequence = faObj.seq.reverse_complement().tostring()
        f.close()
    except ValueError, v:
        if v[0] == 'No records found in handle':
            return '',''
    return (candidateSequence,rcCandidateSequence)
    

	
def recursiveReplace(rule,target,tmpOffTargets,tmpStr):
    if rule[len(tmpStr)] == 'N':   ##Is current position an N?
        for i in 'ACTG':
            tmpStr += i
            if len(tmpStr)==len(target):  ## tmpStr appended to tmpOffTargets
                tmpOffTargets.append(tmpStr)
                tmpStr=tmpStr[:-1]
            else:   
                recursiveReplace(rule,target,tmpOffTargets,tmpStr)
                tmpStr=tmpStr[:-1]
    else:
        tmpStr += target[len(tmpStr)]
        #if tmpStr == target:
        #    tmpStr=tmpStr[:-1]
        if len(tmpStr) == len(target):
            tmpOffTargets.append(tmpStr)
            tmpStr=tmpStr[:-1]
        else:
            recursiveReplace(rule,target,tmpOffTargets,tmpStr)
            tmpStr=tmpStr[:-1]

		


	
	
# This function reads a template HTML file and creates an output based off it.
# if offline == True, all the .css files, .js files as well as JSON files are incorporated into the one standalone HTML file.
# if offline == True and otherwise, relevant information is incorporated into the sidebar of the HTML file.
def createHtmlFile(rule,seed,whereabouts,jobTitle,path):
    
    # Open template and output file
    new = open('{}index.html'.format(path), 'w')
    template = open('templates/template.html', 'r')
    # Create regex rules to scan for .css and .js references
    cssMatch = re.compile(r"[^\'| |\"]*\.css")
    jsMatch = re.compile(r"[^\'| |\"]*\.js")
    placeholder = re.compile('(\$:)[^\W]*')
    formattedRule = makeSeq(rule,rule,seed)
    
    if offline == True:
        for line in template:
            if cssMatch.search(line):
                path = cssMatch.search(line).group(0)
                new.write('<style>\n')
                stylesheet = open('static/css/'+(path.split('/')[-1]),'r')
                for i in stylesheet:
                    new.write(i)
                stylesheet.close()
                new.write('</style>\n')
                
            elif jsMatch.search(line):
                path = jsMatch.search(line).group(0)
                new.write('<script>\n')
                if 'tables.js' not in path:
                    javascript = open('static/js/'+(path.split('/')[-1]),'r')
                else:
                    javascript = open('output/'+(path.split('/')[-1]),'r')
                for i in javascript:
                    new.write(i)
                javascript.close()
                new.write('</script>\n')

            elif placeholder.search(line) is not None:
                if placeholder.search(line).group(0).split(':')[1] == 'jobName':
                    new.write(line.replace(placeholder.search(line).group(0), jobTitle))

                elif placeholder.search(line).group(0).split(':')[1] == 'rule':
                    new.write(line.replace(placeholder.search(line).group(0), formattedRule))
                elif placeholder.search(line).group(0).split(':')[1] == 'whereabouts':
                    if whereabouts[1] != '':
                        new.write(line.replace(placeholder.search(line).group(0),'{}:{} ({})'.format(whereabouts[1],str(whereabouts[2]),whereabouts[0])))
                    else:
                        new.write(line.replace(placeholder.search(line).group(0),'Could not locate candidate sequence in reference genome.'))
                elif placeholder.search(line).group(0).split(':')[1] == 'length':
                    try:
                        new.write(line.replace(placeholder.search(line).group(0),str(whereabouts[3])))
                    except IndexError:
                        new.write(line.replace(placeholder.search(line).group(0),str(whereabouts[0])))
            else:
                new.write(line)
    else:
        for line in template:

            # This line instructs the table-load JS function to load from a file, instead of a var.
            if '</head>' in line:
                new.write(' <script>var online = true;</script>\n</head>\n')
            
            if placeholder.search(line) is not None:
                if placeholder.search(line).group(0).split(':')[1] == 'jobName':
                    new.write(line.replace(placeholder.search(line).group(0), jobTitle))

                elif placeholder.search(line).group(0).split(':')[1] == 'rule':
                    new.write(line.replace(placeholder.search(line).group(0), formattedRule))
                elif placeholder.search(line).group(0).split(':')[1] == 'whereabouts':
                    if whereabouts[1] != '':
                        new.write(line.replace(placeholder.search(line).group(0),'{}:{} ({})'.format(whereabouts[1],str(whereabouts[2]),whereabouts[0])))
                    else:
                        new.write(line.replace(placeholder.search(line).group(0),'Could not locate candidate sequence in reference genome.'))
                elif placeholder.search(line).group(0).split(':')[1] == 'length':
                    try:
                        new.write(line.replace(placeholder.search(line).group(0),str(whereabouts[3])))
                    except IndexError:
                        new.write(line.replace(placeholder.search(line).group(0),str(whereabouts[0])))
            else:
                new.write(line)



# Create JSON file of offTargets
# 

def createOffTargetJSON(candidateTargets,potentialOffTargets,offTargSummary,rule,H,ucscVars,path):
    #OFFLINE MODE
    if (offline == True):
        #H = 1    # To keep file size small, only writes offtargets with H of <=1
        displayedCandidateTargets = open('output/tables.js', 'r')
        f = open('output/otables.js', 'w')
        f.write('var offTargetData = {\n')
        for i in range(1,9+H):
            displayedCandidateTargets.next()
        for line in displayedCandidateTargets:
            current = 0
            key= '{},{}'.format(line[2:8],str('%04d' % current))
            f.write('{}:['.format(line[2:8]))
            if key not in potentialOffTargets:
                f.write('   ')
            while key in potentialOffTargets:
                if ((len(potentialOffTargets[key][6])+1)/6 <= H):    #Only writes up to specified Hamming distance
                    if potentialOffTargets[key][0] == '+':
                        strand = '+'
                        #subOffTarget = Seq(potentialOffTargets[key][3]).reverse_complement().tostring()
                        subOffTarget = Seq(potentialOffTargets[key][3]).tostring()
                        if potentialOffTargets[key][6] != '':    # if Hamming of off-target is > 0
                            for sub in potentialOffTargets[key][6].split(','):    # for each mismatch
                                subOffTarget = subOffTarget[:len(rule)-int(sub.split(':')[0])-1] + sub.split(':')[1][-1] + subOffTarget[len(rule)-int(sub.split(':')[0]):]
                        prettySeq = matching(candidateTargets[key.split(',')[0]][0][-len(rule):],subOffTarget)
                        gc=calcGC(subOffTarget)
                    else:
                        strand = '-'
                        subOffTarget = potentialOffTargets[key][3]
                        if potentialOffTargets[key][6] != '':
                            for sub in potentialOffTargets[key][6].split(','):
                                subOffTarget = subOffTarget[:len(rule)-int(sub.split(':')[0])-1] + sub.split(':')[1][-3] + subOffTarget[len(rule)-int(sub.split(':')[0]):]
                        prettySeq = matching(candidateTargets[key.split(',')[0]][0][-len(rule):],subOffTarget)
                        gc=calcGC(subOffTarget)

                    f.write('["{}","{}","{}","{}","{}","{}","<a href=\'http://genome.ucsc.edu/cgi-bin/hgTracks?position={}:{}-{}\' target=\'_blank\'>GB</a>"],\n'.format(
                        prettySeq,(len(potentialOffTargets[key][6])+1)/6,strand,potentialOffTargets[key][1],int(potentialOffTargets[key][2])+1,gc,potentialOffTargets[key][1],
                        int(potentialOffTargets[key][2])+1,int(potentialOffTargets[key][2])+len(rule)))
                current +=1
                key= '{},{}'.format(line[2:8],str('%04d' % current))                
            #f.seek(-3,2)
            f.write('\n],')
        #f.seek(-7,2)
        f.write('}        ')
        f.close()
        
    #ONLINE MODE
    else:
        displayedCandidateTargets = open('{}tables.js'.format(path), 'r')
        for i in range(1,12):
            displayedCandidateTargets.next()
        for line in displayedCandidateTargets:
            current = 0
            key= '{},{}'.format(line[2:8],str('%04d' % current))
            f = open('{}json/{}.json'.format(path,line[2:8]), 'w')
            f.write('{\n"aaData": [   \n')
            while key in potentialOffTargets:

                if (1==1):#((len(potentialOffTargets[key][6])+1)/6 <= H): #Only writes up to specified Hamming distance
                    if potentialOffTargets[key][0] == '-':
                        strand = '+'
                        subOffTarget = potentialOffTargets[key][3]
                        if potentialOffTargets[key][6] != '':
                            for sub in potentialOffTargets[key][6].split(','):
                                subOffTarget = subOffTarget[:len(subOffTarget)-1-int(sub.split(':')[0])] + sub.split(':')[1][-3] + subOffTarget[len(subOffTarget)-int(sub.split(':')[0]):]      
                        prettySeq = matching(candidateTargets[key.split(',')[0]][0][-len(rule):],subOffTarget)
                        gc=calcGC(subOffTarget)
                    else:
                        strand = '-'
                        subOffTarget = Seq(potentialOffTargets[key][3]).reverse_complement().tostring()
                        if potentialOffTargets[key][6] != '':
                            for sub in potentialOffTargets[key][6].split(','):
                                subOffTarget = subOffTarget[:len(subOffTarget)-1-int(sub.split(':')[0])] + sub.split(':')[1][-1] + subOffTarget[len(subOffTarget)-int(sub.split(':')[0]):]
                        prettySeq = matching(candidateTargets[key.split(',')[0]][0][-len(rule):],subOffTarget)
                        gc=calcGC(subOffTarget)
                        
                    f.write('["{}","{}","{}","{}","{}","{}","<a href=\'http://genome.ucsc.edu/cgi-bin/hgTracks?clade={}&org={}&db={}&position={}:{}-{}\' target=\'_blank\'>GB</a>"],\n'.format(
                        prettySeq,(len(potentialOffTargets[key][6])+1)/6,strand,potentialOffTargets[key][1],int(potentialOffTargets[key][2])+1,gc,ucscVars[0],ucscVars[1],ucscVars[2],potentialOffTargets[key][1],
                        int(potentialOffTargets[key][2])+1,int(potentialOffTargets[key][2])+len(rule)))
                current +=1
                key= '{},{}'.format(line[2:8],str('%04d' % current))  
            f.seek(-3,2)
            f.write('\n]\n}')
            f.close()


#Create JSON file of candidateTargets
def createTargetJSON(candidateTargets, offTargSummary, rule, hamming, seed,path):

    #Open file and write header information
    f = open('{}tables.js'.format(path), 'w')
    f.write('var candidateTargetColumns = [\n{"sTitle":"Target Id","sToolTip":"Unique id for candidate targets"},\n' + \
            '{"sTitle":"Strand","sToolTip":"Candidate sequence strand candidate target is present in, + for forward strand, - for reverse"},\n' + \
            '{"sTitle":"Offset","sType":"numeric","sToolTip":"0-based offset of left-most character in candidate target, into the candidate sequence"},\n')
    f.write('{"sTitle":"H=0 Off-targets","sType":"numeric","sToolTip":"Number of potential off-targets at a Hamming distance of 0"},\n' + \
            '{"sTitle":"H=1 Off-targets","sType":"numeric","sToolTip":"Number of potential off-targets at a Hamming distance of 1"},\n' + \
            '{"sTitle":"H=2 Off-targets","sType":"numeric","sToolTip":"Number of potential off-targets at a Hamming distance of 2"},\n' + \
            '{"sTitle":"H=3 Off-targets","sType":"numeric","sToolTip":"Number of potential off-targets at a Hamming distance of 3"},\n')
    f.write('{"sTitle":"Target Sequence","bSortable":false,"sClass":"sequence","sToolTip":"Nucleotide sequence of the candidate target, red for Ns, green for ACTGBs in seed, blue for ACTGBs out of seed"}\n]\nvar candidateTargetData = [ \n')
    
	#Write a line for each and every candidate target, provided that H=0 is <=25
    for key in candidateTargets.keys():
        if offTargSummary[key][0] <= 25:
            hammings = ''
            for count in range(0,4):
                hammings+=(str(offTargSummary[key][count])+',')
            prettySeq = makeSeq(candidateTargets[key][0],rule,seed)
            f.write('["{}","{}",{},{}"{}"]'.format(
                key,candidateTargets[key][3],candidateTargets[key][1],hammings,prettySeq))
            f.write(',\n')
    
	#Remove last comma and close file
    f.seek(-3,2)
    f.write(']\n')
    f.close()




# matching(seq1,seq2)
# This function compares the two input sequences and returns a HTML formatted string containing seq2.
# Adjacent matching characters are placed in a span with class 'g'.
# Adjacent mismatch characters are placed in a span with class 'r'.
# This allows the CSS to specify formatting (text colour in this case) of matches and mismatches.
def matching(seq1,seq2,count=0,string='',flag=''):
    if count < len(seq2):
        if count == 0:
            string = "5'-"
        if seq2[count]==seq1[count].upper():
            if flag == 'match':
                string = string + seq2[count]
                string = matching(seq1,seq2,count+1,string,'match')
                return string
            elif flag == 'mismatch':
                string = string + "</span><span class='g'>" + seq2[count]
                string = matching(seq1,seq2,count+1,string,'match')
                return string
            else:
                string = string + "<span class='g'>" + seq2[count]
                string = matching(seq1,seq2,count+1,string,'match')
                return string   
        else:
            if flag == 'match':
                string = string + "</span><span class='r'>" + seq2[count]
                string = matching(seq1,seq2,count+1,string,'mismatch')
                return string
            elif flag == 'mismatch':
                string = string + seq2[count]
                string = matching(seq1,seq2,count+1,string,'mismatch')
                return string
            else:
                string = string + "<span class='r'>" + seq2[count]
                string = matching(seq1,seq2,count+1,string,'mismatch')
                return string                
    else:
        string = string+"</span>-3'"
        return string


# Makes an HTML formatted string of seq, based on rule.
# Different classes allow CSS to specify colouring of each span.
def makeSeq(seq,rule,seed,string='',count=0,lastChar=''):
    if count < len(seq):
        
        if count == 0:
            string = "5'-"
            #Adds black 5' characters from outside rule to pad to 23nt
            if len(seq)>len(rule):
                string = string + seq[0 : (len(seq)-len(rule))]
                count+=len(seq)-len(rule)
                
        #Defines 'position', a flag to specify whether count is currently a seed position or not, or just transitioned.   
        if count < len(seq)-seed:
            position = 'seed'
        elif count == len(seq)-seed:
            position = 'edge'
        else:
            position = ''

        # If the current position is an 'N' the algorithm enters this if statement, and the appropriate child if statement according to the flags 
        if rule[count-(len(seq)-len(rule))] == 'N':
            if lastChar == 'N':
                string = string+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'N')
                return string
            elif lastChar == '':
                string = string+"<span class='r'>"+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'N')
                return string
            else:
                string = string+"</span><span class='r'>"+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'N')
                return string
            
        else:
            if lastChar == 'B' and position == '':
                string = string+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'B')
                return string
            elif lastChar == 'B' and position == 'seed':
                string = string+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'B')
                return string
            if lastChar == '' and position == 'seed':
                string = string+"<span class='b'>"+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'B')
                return string
            if lastChar == 'N' and position == 'seed':
                string = string+"</span><span class='b'>"+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'B')
                return string
            else:
                string = string+"</span><span class='g'>"+seq[count]
                string = makeSeq(seq,rule,seed,string,count+1,'B')
                return string
            
    else:
        string = string+"</span>-3'"
        return string


# Calculates GC content
# Simply calculates number of Gs and Cs and divides this no. by the length of the sequence.
# Is case insensitive
def calcGC(seq):
    i = 0.0
    for j in seq.upper():
        if j == 'G' or j == 'C':
            i=i+1
    return ('%.2f') % (i/len(seq)*100)


# Creates a FASTA file with a seperate entry for every sequence in the dictionary 'sequences'.
def createFastaFile(sequences,path):
    faFileName = '{}output/potentialofftargetstrings.fa'.format(path)
    f = open(faFileName, 'w')
    for i in sequences:
        for j in sequences[i]:
            f.write('>{}\n{}\n'.format(i,Seq(j).reverse_complement().tostring()))
            #f.write('>{}\n{}\n'.format(i,Seq(j).tostring()))
    f.close()


# Calls Bowtie with user-specified parameters.
# Input FASTA file name is the same as createFastaFile()
def bowtieSearch(refGenome, H, seed,path):
    inputFile = '{}output/potentialofftargetstrings.fa'.format(path)
    alignments = 200
    if seed>=5:
        call= 'bowtie {} -f {} -k {} -l {} -n {} -e 110 {}output/output.out'.format(refGenome,inputFile,alignments,seed,H,path)
        #call= 'bowtie {} -f {} -k {} -n 0 -l {} -e 100 {}output/output.out'.format(refGenome,inputFile,alignments,seed,path)
    else:
        call= 'bowtie {} -f {} -k {} -v 3 {}output/output.out'.format(refGenome,inputFile,alignments,path)
    print call
    proc = sp.Popen(call,shell=True,stderr=sp.PIPE,stdout=sp.PIPE)
    stdout_value, stderr_value= proc.communicate()
    print stderr_value



def createOutputFiles(candidateTargets, potentialOffTargets, offTargSummary, rule, H, seed,whereabouts, jobTitle='randomJob',ucscVars=['','',''], path='output/'):
    print('Creating files...\n')
    createTargetJSON(candidateTargets, offTargSummary, rule, H, seed,path)
    createOffTargetJSON(candidateTargets, potentialOffTargets, offTargSummary, rule,H,ucscVars,path)
    createHtmlFile(rule,seed,whereabouts,jobTitle,path)
    if offline == True:
        os.remove('output/potentialofftargetstrings.fa')
        os.remove('output/output.out')
        os.remove('output/otables.js')
        os.remove('output/tables.js')
    #else:
        os.remove(path+'output/output.out')
        os.remove(path+'output/potentialofftargetstrings.fa')
        os.rmdir(path+'output')

# Creates a FASTA file of potential off-targets, calls Bowtie with this file as an input and processes Bowtie's output.
# Returns summary, a summary of potential off-targets at each H for each candidate target and
# potentialOffTargets, a dictionary of every potential off-target.
# This function removes the potential off-target if it is the same as the input.
def predictPotentialOffTargets(candidateTargets,potentialOffTargetStrings, refGenome, H,seed,rule,whereabouts,path=''):
    print('Locating off-targets...\n')
    createFastaFile(potentialOffTargetStrings,path)
    bowtieSearch(refGenome,H,seed,path)
    ht = {0:0,1:0,2:0,3:0}
    prevLine='t_0001'
    potentialOffTargets = {}
    summary={}
    i=0

    with open('{}output/output.out'.format(path)) as tsv:
        for line in csv.reader(tsv, dialect='excel-tab'):
            
            #Does this only when processing the first potential off-target for each candidate target.
            if prevLine != line[0]:
                summary[prevLine]=[ht[0],ht[1],ht[2],ht[3]]
                i,ht[0],ht[1],ht[2],ht[3]=0,0,0,0,0
                
            #Adds the potential off-target to the dictionary.
            potentialOffTargets[line[0]+','+('%04d' % i)]=line[1:8]+[line[0]]
            prevLine = line[0]
            flag = 0
            currentHamming = (len(line[7])+1)/6
            ht[currentHamming] +=1
            
            #Removes false potential off-targets, i.e. if potential off-target is the candidate target or mismatch is in N position            
            if currentHamming == 0: # if Hamming of offtarget is 0
                if line[2] == whereabouts[1]: # if in same chromosome
                    if int(whereabouts[2]) <= int(line[3]) <= int(whereabouts[2])+whereabouts[3]: #If in same chromosomal offset range
                        del potentialOffTargets[line[0]+','+('%04d' % i)] # remove false off-target from dictionary
                        ht[currentHamming] -=1
                        i -=1      
            else:
                for m in re.finditer( 'N', rule ):
                    for o in line[7].split(','):
                        if len(rule)-m.end() == int(o.split(':')[0]):
                            flag = 1  # flag is to ensure delete only called once, since this if may be triggered multiple times
                if flag == 1:
                    del potentialOffTargets[line[0]+','+('%04d' % i)]
                    i -= 1
                    ht[currentHamming]-=1             
             
            i+=1
        summary[prevLine]=[ht[0],ht[1],ht[2],ht[3]] # does for last line
        
    # Checks that every one is in summary, i.e. if in case of Bowtie not locating a match...
    for i in potentialOffTargetStrings:
        if i not in summary:
            summary[i]=[0,0,0,0]
            
    return summary,potentialOffTargets


# Generate potential off-targets with different nucleotides at N positions
def createPotentialOffTargetStrings(rule, candidateTargets):

    if len(rule) <= 23:
        windowSize = 23
    else:
        windowSize = len(rule)
    
    potentialOffTargetStrings = {}    ## Dictionary of off-targets, for every target.
    for target in candidateTargets:
        tmpStr = ''     ## Appended to tmpOffTargets when length equal to rule length
        tmpOffTargets = []  ## Holds off-targets for current target, appended to potentialOffTargetStrings
        recursiveReplace(rule,candidateTargets[target][0][windowSize-len(rule):],tmpOffTargets,tmpStr)
        potentialOffTargetStrings[target] = tmpOffTargets
    return potentialOffTargetStrings
                    


    
# Find target sites and add to dictionary, 'candidateTargets'.
def findCandidateTargets(rule,faname):
    print('Locating candidate targets...\n')
    targetRe = createCandTargRegex(rule)
    candidateSequence,rcCandidateSequence = createCandSeqStr(faname)
    GC = 0
    c = 1

    #Since scanning in sliding window, a rule length 23 or under sets window to size 23 since user is probably scanning for CRISPR targets
    if len(rule) <= 23:
        windowSize = 23
    else:
        windowSize = len(rule)
    
    candidateTargets = {}
    
    # Scans string for candidate targets
    for i in range(0,len(candidateSequence)-windowSize+1):               ## Sliding window of len(rule)
        if targetRe.match(candidateSequence[i:i+windowSize]) != None:    ## If there IS match with regex 
            GC=calcGC(candidateSequence[i:i+windowSize])                 ## Also calculate GC content
            candidateTargets['t_'+str('%04d' % c)] = (targetRe.match(candidateSequence[i:i+windowSize]).group(),i,GC,'+')
            c+=1
            
    # Scans reverse complement string for candidate targets
    for i in range(0,len(rcCandidateSequence)-windowSize+1):               ## Sliding window of len(rule)
        if targetRe.match(rcCandidateSequence[i:i+windowSize]) != None:    ## If there IS match with regex 
            GC=calcGC(rcCandidateSequence[i:i+windowSize])                 ## Also calculate GC content
            candidateTargets['t_'+str('%04d' % c)] = (targetRe.match(rcCandidateSequence[i:i+windowSize]).group(),i,GC,'-')
            c+=1
            
    return candidateTargets

#Runs a Bowtie search to locate the candidate sequence within the reference genome
def findCandidateSequenceLocation(faname,refGenome):
    candidateSequence,rcCandidateSequence = createCandSeqStr(faname)
    candidateSequenceLength = len(candidateSequence)
    if candidateSequenceLength<200:
        call= 'bowtie {} -c {}'.format(refGenome,candidateSequence)
    else:
        call= 'bowtie {} -c {}'.format(refGenome,candidateSequence[0:199])
    proc = sp.Popen(call,shell=True,stderr=sp.PIPE,stdout=sp.PIPE)
    stdout_value, stderr_value= proc.communicate()
    bowtieList = stdout_value.split('	')[1:4]
    if len(bowtieList) == 3:
        bowtieList.append(candidateSequenceLength)
    else:
        bowtieList = ['','','']
        bowtieList.append(candidateSequenceLength)
    return bowtieList
	
                

def main(args):
    #Defaults
    rule = 'BBBBBBBBBBBBBBBBBNGG'
    faName = 'input.fa'
    refGenome = '/bowtie-1.0.0/genomes/hg19'
    mismatches = 0;
    threePrimeLength = 0;

    #Argument parser
    parser = argparse.ArgumentParser(
        description="Searches a candidate gene for potential targets and generates a list of likely off-targets for each target.")
    #Positional arguments
    parser.add_argument('faPath',default=faName,help="Relative path of a FASTA file containing a candidate sequence, i.e. 'input.fa'. The file must contain only standard DNA characters (ACTG) and only one sequence.'")
    parser.add_argument('refGenome',default=refGenome,help="Absolute path of Bowtie indxed reference genome. i.e. '/bowtie-1.0.0/genomes/hg19'")
    #Optional arguments
    parser.add_argument('-m', '--mismatches', type=int, choices=xrange(4), default=mismatches,
                        help='This value specifies the maximum number of mismatches allowed between a sequence and a candidate target, for that sequence to be considered \
                            a potential off-target. Mismatches are only allowed in the 5\' region, i.e. outside of the region specified below. The number of mismatches \
                            is referred to as the Hamming distance (H). The results page will display the number of potential off-targets at each Hamming distance in separate \
                            columns. (default: {})'.format(mismatches))
    parser.add_argument('-l', '--threePrimeLength', type=int, default = threePrimeLength, metavar='{0,5-23}',
                        help='This value specifies the number of 3\' nucleotides that must match exactly, between a sequence and a candidate target, for that sequence to be considered\
                            a potential off-target. (default: {})'.format(threePrimeLength))
    parser.add_argument('-r', '--rule', default = rule,
                        help='The rule defines the sequences that CRISPR-search will consider as candidate targets, and subsequently, potential off-targets. Allowed characters are A C T G B and N.\
                            A string from the candidate sequence is only required to match the rule at A C T and G positions, to be considered a candidate target.\
                            A string from the reference genome will be considered a potential off-target if it matches a candidate target at A C T G and B positions. \
                            A match between these two strings at N positions is not required. (default: {})'.format(rule))
    args = parser.parse_args()



    #important functions that do stuff
    start = time.time()
    whereabouts = findCandidateSequenceLocation(args.faPath,refGenome)
    candidateTargets = findCandidateTargets(args.rule, args.faPath)
    potentialOffTargetStrings = createPotentialOffTargetStrings(args.rule, candidateTargets)
    offTargSummary,potentialOffTargets = predictPotentialOffTargets(candidateTargets, potentialOffTargetStrings, args.refGenome, args.mismatches, args.threePrimeLength,rule,whereabouts)
    createOutputFiles(candidateTargets, potentialOffTargets, offTargSummary, args.rule, args.mismatches, args.threePrimeLength, whereabouts)
    elapsed = (time.time() - start)
    #print elapsed  



offline=False
if __name__ == '__main__':
    offline=True
    main(sys.argv)
